package cn.bellychang.bobo.arraylist;

import java.util.Arrays;

/**
 * @author ChangLiang
 * @date 2020/9/6
 */
public class ArrayList<E> {

    private static final int INITIAL_SIZE = 2;

    /**
     * 扩容时扩容为原来的2倍 缩容为原来的1/2
     */
    private static final int RANGE_FACTOR = 2;

    /**
     * 缩容条件
     */
    private static final int RANGE_REDUCE_FACTOR = 4;

    private E[] array;

    /**
     * array中元素个数
     */
    private int size;

    public ArrayList() {
        this(INITIAL_SIZE);
    }

    @SuppressWarnings(value = "unchecked")
    public ArrayList(int initSize) {
        array = (E[]) new Object[initSize];

        // 这样强转是可以的
//        this.array = (E[]) new Object[capacity];
    }

    public int getCapacity() {
        return array.length;
    }

    public int getSize() {
        return size;
    }

    public void add(int index, E e) {
        // checkRange 查看是否需要扩容
        checkRange();

        checkIndexValid(index);

        // 需要移动数据
        if (index < size) {
            copyArrayRange(index, true);
        }
        array[index] = e;
        size++;
    }

    private void checkIndexValid(int index) {
        // 这里如果使用array.length 那么就要先检查容量 看是否需要扩容
        // 如果这里使用size 那么就可以后检查容量 看是否需要扩容 如果index > size 就支持addLast了
        if (index < 0 || index >= array.length) {
            throw new RuntimeException("index out of bound");
        }
    }

    private void copyArrayRange(int oldIndex, boolean isExtend) {
        // 可以使用System.arraycopy(array, 0, target, 0, array.length - 1); 优化
        if (isExtend) {
            for (int i = size; i > oldIndex; i--) {
                array[i] = array[i - 1];
            }
        } else {
            for (int i = oldIndex; i < size - 1; i++) {
                array[i] = array[i + 1];
            }
        }
    }

    public void addFirst(E e) {
        add(0, e);
    }

    public void addLast(E e) {
        add(this.getSize(), e);
    }

    /**
     * 考虑是否需要扩容或缩容
     */
    private void checkRange() {
        if (this.getSize() >= array.length) {
            array = Arrays.copyOf(array, array.length * RANGE_FACTOR);
        }
        // 缩容的条件 防止震荡
        if (this.getCapacity() > INITIAL_SIZE && this.getSize() * RANGE_REDUCE_FACTOR < array.length) {
            array = Arrays.copyOf(array, array.length / RANGE_FACTOR);
        }
    }

    public E get(int index) {
        checkIndexValid(index);
        return array[index];
    }

    public E remove(int index) {
        checkIndexValid(index);
        E result = this.get(index);
        // 判断是否需要移动
        if (index < size - 1) {
            copyArrayRange(index, false);
        }
        size--;
        checkRange();
        return result;
    }

    public E removeFirst() {
        return this.remove(0);
    }

    public E removeLast() {
        return this.remove(size - 1);
    }

    @Override
    public String toString() {

        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < size; i++) {
            builder.append(array[i].toString());
            builder.append("->");
        }

        return builder.toString().endsWith("->") ? builder.toString().substring(0, builder.toString().length() - 2) : builder.toString();
    }

    public Iterator<E> iterator() {
        return new Iterator<E>() {

            int index = 0;

            @Override
            public boolean hasNext() {
                return index < size;
            }

            @Override
            public E next() {
                E e = array[index];
                index++;
                return e;
            }
        };
    }

    public Iterator<E> reverseIterator() {
        return new Iterator<E>() {

            int index = size - 1;

            @Override
            public boolean hasNext() {
                return index >= 0;
            }

            @Override
            public E next() {
                E e = array[index];
                index--;
                return e;
            }
        };
    }


}